图片(Image)
Flutter 中加载图片的控件是 Image
,图片来源可以是 asset
、文件
、网络
以及内存
。
图片来源的不同,加载图片的方式也不同,Flutter 提供了一个接口 ImageProvider
,它是一个抽象类,定义了图片数据获取的接口的 load()
方法,不同的来源,需要实现不同的 ImageProvider
的实现类:
AssetImage
,用于加载 Asset 中的图片NetworkImage
,用于加载网络图片FileImage
,用于加载存储中的图片文件MemoryImage
,用于加载内存中的文件
看一下源码:
const Image({
Key key,
@required this.image,
this.frameBuilder,
this.loadingBuilder,
this.semanticLabel, //图像的语义描述,用于向Andoid上的TalkBack和iOS上的VoiceOver提供图像描述
this.excludeFromSemantics = false, //是否启用图像的语义描述
this.width, //控件宽度
this.height, //控件高度
this.color, //如果为非null,则使用colorBlendMode将此颜色与每个图像像素混合
this.colorBlendMode, //用于将color与此图像组合。
this.fit, //图片如何在Image控件中显示
this.alignment = Alignment.center, //对齐方式
this.repeat = ImageRepeat.noRepeat, //当图片没完全覆着Image时,如何绘制未覆盖的任何部分,默认值为noRepeat
this.centerSlice, //指定中心区域进行九个补丁图像,在中心切片内的图像区域将水平和垂直拉伸,以使图像适合其目的地。
this.matchTextDirection = false, //是否在TextDirection的方向上绘制图像。
this.gaplessPlayback = false, //当图像提供者发生变化时,是继续显示旧图像,默认不显示!
this.filterQuality = FilterQuality.low, //图像过滤器的质量级别。(渲染模式的质量)
})
属性的详细解释请看来自这里 CSDN - 陈英有 - Flutter Image 参数详解,请移步原作者,这里仅作备份,以防作者删除。
semanticLabel
是用于向安卓上的TalkBack
和苹果上的VoiceOver
提供图像描述talkback
是一款由谷歌官方开发的系统软件,它的定位是帮助盲人或者视力有障碍的用户提供语言辅助Voiceover
功能是苹果公司推出的一种语音辅助程序
fit
用来控制图片如何在 Image 控件中显示,下面是这个属性的选项:BoxFit.fill
图片按照指定的大小在 Image 中显示,拉伸显示图片,不保持原比例,填满 Image
BoxFit.contain
以原图正常显示为目的,如果原图大小大于 Image 的 size,就按照比例缩小原图的宽高,居中显示在 Image 中。如果原图 size 小于 Image 的 size,则按比例拉升原图的宽和高,填充 Image 一边并居中显示。
BoxFit.cover
以原图填满 Image 为目的,如果原图 size 大于 Image 的 size,按比例缩小,居中显示在 Image上。如果原图 size 小于 Image 的size,则按比例拉升原图的宽和高,填充 Image 居中显示。
BoxFit.fitWidth
以原图正常显示为目的,如果原图宽大小大于(小于)Image 的宽,就缩小(放大)原图的宽与 Image 一致,居中显示在 Image 中。
BoxFit.fitHeight
以原图正常显示为目的,如果原图高大小大于(小于)Image 的高,就缩小(放大)原图的高与 Image 一致,居中显示在 Image 中。
BoxFit.none
保持原图的大小,显示在 Image 的中心。当原图的 size 大于 Image 的 size 时,多出来的部分被截掉
BoxFit.scaleDown
以原图正常显示为目的,如果原图大小大于 Image 的 size,就按照比例缩小原图的宽高,居中显示在 Image 中。如果原图 size 小于 Image 的 size,则不做处理居中显示图片。
repeat
用来设置当图片没完全覆着 Image 时,如何绘制未覆盖的任何部分,默认值为noRepeat
,有以下值可选:ImageRepeat.repeat
在 x 和 y 方向上重复图像,直到填充框。
ImageRepeat.repeatX
在 x 方向上重复图像,直到水平填充框
ImageRepeat.repeatY
在 y 方向重复图像,直到垂直填充框
ImageRepeat.noRepeat
将未覆盖部分保持透明
从 Asset 中加载图片
我们知道,当我们的 App 打包时,Asset 目录中的文件是不进行压缩的,在 asset
目录我们经常会放一些基本数据(例如 json 文件),一些图片和图片之类的。
源码就不看了,和 Image 差不多,之多了一个 name
属性,用于指定图片名称。
在 Flutter 中如何访问它们呢?还记得之前的章节中的自定义 Text 字体吗?加载 Asset 图片和自定义字体步骤差不多:
在
pubspec.yaml
文件中指定 asset 目录资源的位置需要注意 的是,这个
asset
目录和 Android 项目中的assets
目录不是一回事,需要自己创建目录,并且对于目录的名称是没有要求的,不过通常我们会在pubspec.yaml
同级目录创建一个assets
目录,然后再在这个目录里划分images
、fonts
之类的。例如目录划分是这样的:你的 APP |- assets | |- images | |- icon.png | |- fonts | |- xxxxx |- pubspec.yaml
在
pubspec.yaml
中就可以这样声明:flutter: assets: - assets/images/icon.png
然后就可以使用图片了:
Image(image: AssetImage("assets/images/icon.png"), width: 100.0),
Flutter 还提供了一种简便的方式:
Image.asset("assets/images/icon.png", width: 100.0),
从网络中加载图片
源码和 Image 也基本类似,只是多了 src
和 headers
属性,前者用于标识图片路径,后者用于标识请求图片时自定义的 HTTP 请求参数。
Image.network(
"https://www.li-xyz.com/content/images/2019/08/2449319331.png",
width: 100.0),
Image(
image: NetworkImage(
"https://www.li-xyz.com/content/images/2019/08/2449319331.png",
),
width: 100,
),
从文件加载图片
其源码和 Image 类似,只是多了一个 File
属性,它是一个对象,用于表示图片的文件。
这里上一个例子,里面用到了 image_picker
包,以后会讲到:
class _FileImageDemoState extends State<MyHomePage> {
File _image;
Future getImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_image = image;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Center(
child: _image == null
? Text('您还未选择任何图片.')
: Image.file(_image,scale: 0.5,fit: BoxFit.cover,),
),
FlatButton(
onPressed: getImage,
child: Text('点击选择图片',style: TextStyle(color: Colors.white),),
color: Colors.lightBlue
)
],
);
}
}
加载内存中的图片
主要解析 bytes
参数,其他和 Image 一致!
bytes
是 Uint8List
获取的 ImageStream
class _MemoryImageDemoState extends State<MyHomePage> {
Uint8List bytes;
void initState() {
super.initState();
rootBundle.load('assets/images/icon.png').then((data) {
if (mounted) {
setState(() {
bytes = data.buffer.asUint8List();
});
}
});
}
@override
Widget build(BuildContext context) {
final decoration = BoxDecoration(
image: bytes == null
? null
: DecorationImage(
image: MemoryImage(bytes,scale: 1.0),
),
);
return Container(
width: 300.0,
height: 300.0,
decoration: decoration,
);
}
}
图标(ICON)
Flutter中,可以像Web开发一样使用 iconfont
,iconfont
即字体图标
,它是将图标做成字体文件,然后通过指定不同的字符而显示不同的图片。
在字体文件中,每一个字符都对应一个位码,而每一个位码对应一个显示字形,不同的字体就是指字形不同,即字符对应的字形是不同的。而在 iconfont 中,只是将位码对应的字形做成了图标,所以不同的字符最终就会渲染成不同的图标。
在 Flutter 开发中,iconfont
和图片相比有如下优势:
- 体积小:可以减小安装包大小。
- 矢量的:iconfont 都是矢量图标,放大不会影响其清晰度。
- 可以应用文本样式:可以像文本一样改变字体图标的颜色、大小对齐等。
- 可以通过 TextSpan 和文本混用。
使用Material Design字体图标
Flutter默认包含了一套Material Design的字体图标,在pubspec.yaml
文件中的配置如下
flutter:
uses-material-design: true
Material Design所有图标可以在其官网查看:https://material.io/tools/icons/
我们看一个简单的例子:
String icons = "";
// accessible:  or 0xE914 or E914
icons += "\uE914";
// error:  or 0xE000 or E000
icons += " \uE000";
// fingerprint:  or 0xE90D or E90D
icons += " \uE90D";
Text(icons,
style: TextStyle(
fontFamily: "MaterialIcons",
fontSize: 24.0,
color: Colors.green
),
);
运行效果如图3-21所示:
通过这个示例可以看到,使用图标就像使用文本一样,但是这种方式需要我们提供每个图标的码点,这并对开发者不友好,所以,Flutter封装了IconData
和Icon
来专门显示字体图标,上面的例子也可以用如下方式实现:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.accessible,color: Colors.green,),
Icon(Icons.error,color: Colors.green,),
Icon(Icons.fingerprint,color: Colors.green,),
],
)
Icons
类中包含了所有Material Design图标的IconData
静态变量定义。
使用自定义字体图标
我们也可以使用自定义字体图标。iconfont.cn上有很多字体图标素材,我们可以选择自己需要的图标打包下载后,会生成一些不同格式的字体文件,在Flutter中,我们使用ttf格式即可。
假设我们项目中需要使用一个书籍图标和微信图标,我们打包下载后导入:
导入字体图标文件;这一步和导入字体文件相同,假设我们的字体图标文件保存在项目根目录下,路径为"fonts/iconfont.ttf":
fonts: - family: myIcon #指定一个字体名 fonts: - asset: fonts/iconfont.ttf
为了使用方便,我们定义一个
MyIcons
类,功能和Icons
类一样:将字体文件中的所有图标都定义成静态变量:class MyIcons{ // book 图标 static const IconData book = const IconData( 0xe614, fontFamily: 'myIcon', matchTextDirection: true ); // 微信图标 static const IconData wechat = const IconData( 0xec7d, fontFamily: 'myIcon', matchTextDirection: true ); }
使用
Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Icon(MyIcons.book,color: Colors.purple,), Icon(MyIcons.wechat,color: Colors.green,), ], )
运行后效果如图3-22所示: